#include "StdAfx.h"
#include <locale>
#include <cmath>
#include "Utils.hpp"
#include "../Engine/TerrainTileSet.hpp"
#include "../Engine/TerrainTileSplat.hpp"
#include "../Engine/TerrainMaterialManager.hpp"

namespace he
{
	TerrainMaterialManager::TerrainMaterialManager(boost::filesystem::path const &Path)
	{
		boost::filesystem::path const full_path = Path/"data"/"terrain.xml";
		// If file doesn't exist
		if(!boost::filesystem::exists(full_path))
			throw std::runtime_error("Terrain file '" + full_path.string() + "' not found.");
		// Open file
		std::ifstream terrain_file(full_path.string().c_str());
		// Read the content of file
		std::ostringstream file_content;
		file_content << terrain_file.rdbuf();
		// Get the string
		std::string const content_string = file_content.str();
		boost::scoped_array<char> p_array(new char[content_string.size() + 1]);
		strcpy(p_array.get(), content_string.c_str());
		// Parse file
		rapidxml::xml_document<> doc;
		doc.parse<0>(p_array.get());
		// Get the root node
		rapidxml::xml_node<> *p_root = doc.first_node();
		// Get all splats
		for(rapidxml::xml_node<> *p_node = p_root->first_node("splat")->first_node(); p_node != nullptr; p_node = p_node->next_sibling())
		{
			TerrainTileSplatPtr_t p_terrain_splat(new TerrainTileSplat());
			m_TerrainSplatMap[static_cast<unsigned short>(Convert::to_uint32(p_node->first_attribute("id")->value()))] = p_terrain_splat;
			for(rapidxml::xml_node<> *p_splat_item = p_node->first_node(); p_splat_item != nullptr; p_splat_item = p_splat_item->next_sibling())
			{
				p_terrain_splat->add_splat(static_cast<unsigned short>(Convert::to_int32(p_splat_item->first_attribute("id")->value())),
					TextureAtlasInfo_t(static_cast<float>(Convert::to_double(p_splat_item->first_attribute("woffset")->value())),
					static_cast<float>(Convert::to_double(p_splat_item->first_attribute("hoffset")->value())),
					static_cast<float>(Convert::to_double(p_splat_item->first_attribute("width")->value())),
					static_cast<float>(Convert::to_double(p_splat_item->first_attribute("height")->value()))));
			}
		}
		// Get all sets
		for(rapidxml::xml_node<> *p_node = p_root->first_node("set"); p_node != nullptr; p_node = p_node->next_sibling("set"))
		{
			// Get the tile set name
			std::string const set_name = p_node->first_attribute("name")->value();
			TerrainTileSetPtr_t p_terrain_tile_set(new TerrainTileSet(*m_TerrainSplatMap.find(
				static_cast<unsigned short>(Convert::to_int32(p_node->first_attribute("splat")->value())))->second,
				p_node->first_attribute("material")->value()));
			m_MaterialMap[set_name] = p_terrain_tile_set;
			// Get all types
			for(rapidxml::xml_node<> *p_type_node = p_node->first_node()->first_node(); p_type_node; p_type_node = p_type_node->next_sibling())
			{
				// Get the id
				unsigned int const type_id = Convert::to_int32(p_type_node->first_attribute("id")->value());
				// Get all variants
				for(rapidxml::xml_node<> *p_type_variant_node = p_type_node->first_node(); p_type_variant_node; p_type_variant_node = p_type_variant_node->next_sibling())
				{
					// Add tile info
					p_terrain_tile_set->add_type(type_id, 
						TextureAtlasInfo_t(static_cast<float>(Convert::to_double(p_type_variant_node->first_attribute("woffset")->value())),
							static_cast<float>(Convert::to_double(p_type_variant_node->first_attribute("hoffset")->value())),
							static_cast<float>(Convert::to_double(p_type_variant_node->first_attribute("width")->value())),
							static_cast<float>(Convert::to_double(p_type_variant_node->first_attribute("height")->value()))
						)
					);
				}
			}
		}
	}

	TerrainTileSet const &TerrainMaterialManager::get_terrain_set(std::string const &Category) const
	{
		return *m_MaterialMap.find(Category)->second;
	}
}